function bl = setequal(A, B)
  % TODO: convert this so that it returns: 
  %   A if A is a proper subset of B
  %   B if B is a proper subset of A
  %   1 if A == B
  %   0 if none of the above
    bl = false;
    try
        if isstruct(A) && isstruct(B)
            fA = fieldnames(A); fB = fieldnames(B);
            if ~allinboth(fA,fB)
                return
            end
            for f = fA
                f = f{:};
                if ~setequal(A.(f), B.(f))
                    return
                end
            end
          % If I get here, everything checked out!
            bl = true;
%         elseif iscellstr(A) && iscellstr(B)
%             A = unique(A); B = unique(B);
%             if numel(A) ~= numel(B), return; end
%             bl = allinboth(A,B);
%             return
%         elseif iscell(A) && iscell(B)
        elseif (numel(size(A)) < 3) && (numel(size(B)) < 3) % < 2D arrays not supported
            try
                bl = allinboth(A,B); % This is advertised to work if A & B are both
                                     % "numeric or char arrays or cellstr arrays"
            catch ME
              % If above threw an error, try element by element comparison, but only "one deep,"              
              % i.e., not recursively, i.e., we don't want A==B if A = {{'A', 'B'}; {3, 4}} and 
              % B = {'A', 'B', 3, 4}.  Also, the elements of A & B can be, at worst, those things 
              % on which ismember works, namely, "numeric or char arrays or cellstr arrays"
                bl = cmpGenCelArr(A,B) && cmpGenCelArr(B,A); % Since cmpGenCelArr only checks member-
                                                             % ship, must perform test both ways in
                                                             % case A is a proper subset of B
            end
        end
    catch ME
        bl = getReport(ME);
    end
end

function bl = cmpGenCelArr(A, B)
%    bl = false;
    szA = size(A); szB = size(B);
    for i=1:szA(1)
        for j=1:szA(2)
            Atemp = A{i,j};
            for k=1:szB(1)
                for l=1:szB(2)
                    Btemp = B{k,l};
                    bl = allinboth(Atemp, Btemp); % Using allinboth here is what limits A & B
                                                  % in setequal to be, at worst, those things 
                                                  % on which ismember works.
                    if ~bl, return; end
                end
%                if ~bl, break; end
            end
%            if ~bl, break; end
        end
%        if ~bl, break; end
    end    
end

function bl = allinboth(A,B)
    bl = all(ismember(A,B)) && all(ismember(B,A));
end